﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Xml;


namespace TwinHead.Frameworks.Xml
{
    /// <summary>
    /// XML네임스페이스를 취급하는데 도움을 주는 클래스입니다.
    /// </summary>
    public sealed class NamespaceManager
    {
        private string prefix = string.Empty;
        private string url = string.Empty;
        public NamespaceManager()
        {
        }
        /// <summary>
        /// 접두어
        /// </summary>
        public string NamespacePrefix
        {
            get { return this.prefix; }
            set { this.prefix = value; }
        }
        /// <summary>
        /// Validation Url
        /// </summary>
        public string NamespaceUrl
        {
            get { return this.url; }
            set { this.url = value; }
        }

        /// <summary>
        /// 지정한 xml문서에서 NameSpace를 해석하여 반환합니다
        /// </summary>
        public static XmlNamespaceManager GetNameSpace( XmlDocument doc )
        {
            try
            {
                if (doc == null) return null;

                doc.Normalize();
                XmlNameTable nameTable = doc.NameTable;
                XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager( nameTable );
                Hashtable ht = new Hashtable();

                bool isSchema = false;

                XmlReader reader = new XmlNodeReader( (XmlNode)doc );
                while (reader.Read())
                {
                    if (reader.IsStartElement())
                    {
                        if (reader.Name.Equals( "xsd:schema", StringComparison.InvariantCultureIgnoreCase ))
                            isSchema = true;

                        if (ht[reader.Prefix] == null)
                            ht.Add( reader.Prefix, reader.NamespaceURI );
                    }
                }
                reader.Close();

                if (!ht.ContainsKey( "dcterms" ))
                    ht.Add( "dcterms", "http://purl.org/dc/terms/" );

                IDictionaryEnumerator d = ht.GetEnumerator();
                while (d.MoveNext())	// 찾아진 Namespace로 추가
                    nameSpaceManager.AddNamespace( d.Key.ToString(), d.Value.ToString() );

                if (isSchema) // Taginfo만 추출하는게 아니기때문에 필요하다.
                {
                    XmlNode node = doc.SelectSingleNode( "/xsd:schema", nameSpaceManager );
                    foreach (XmlAttribute att in node.Attributes)
                    {
                        if (ht[att.LocalName] == null)
                            ht.Add( att.LocalName, att.Value );
                    }

                    d = ht.GetEnumerator();
                    while (d.MoveNext())
                    {
                        if (!nameSpaceManager.HasNamespace( d.Key.ToString() ))
                        {
                            try
                            {
                                nameSpaceManager.AddNamespace( d.Key.ToString(), d.Value.ToString() );
                            }
                            catch
                            {
                            }
                        }
                    }
                }

                return nameSpaceManager;
            }
            catch
            {
                return null;
            }
        }

        public static XmlNamespaceManager GetNameSpaceForTagInfo( XmlDocument doc )
        {
            try
            {
                if (doc == null) return null;

                doc.Normalize();
                XmlNameTable nameTable = doc.NameTable;
                XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager( nameTable );
                Hashtable ht = new Hashtable();

                XmlReader reader = new XmlNodeReader( (XmlNode)doc );
                while (reader.Read())
                {
                    if (reader.IsStartElement())
                    {
                        if (ht[reader.Prefix] == null)
                            ht.Add( reader.Prefix, reader.NamespaceURI );
                    }
                }
                reader.Close();

                if (!ht.ContainsKey( "dcterms" ))
                    ht.Add( "dcterms", "http://purl.org/dc/terms/" );

                IDictionaryEnumerator d = ht.GetEnumerator();
                while (d.MoveNext())	// 찾아진 Namespace로 추가
                    nameSpaceManager.AddNamespace( d.Key.ToString(), d.Value.ToString() );

                return nameSpaceManager;
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// 주어진 네임스페이스매니저를 통해 xml태그의 어트리뷰트로 사용할 문자열을 반환합니다.
        /// </summary>
        /// <param name="xnsmgr"></param>
        /// <returns></returns>
        public static string GetNamespaceAttributeText( XmlNamespaceManager xnsmgr )
        {
            if (xnsmgr == null) return string.Empty;

            StringBuilder builder = new StringBuilder();

            string prefix = string.Empty;
            string uri = string.Empty;

            // IEnumerator e = (IDictionaryEnumerator)xnsmgr.GetEnumerator();
            IEnumerator e = xnsmgr.GetEnumerator();
            while (e.MoveNext())
            {
                if (e.Current.Equals( "" )) continue;
                prefix = e.Current.ToString();
                if (prefix.Equals( "xmlns", StringComparison.InvariantCulture )) continue;
                //if (prefix.Equals( "xsd" )) continue;
                if (prefix.Equals( "xml", StringComparison.InvariantCulture )) continue;
                uri = xnsmgr.LookupNamespace( prefix );
                builder.AppendFormat( " xmlns:{0}=\"{1}\"", prefix, uri );
            }

            return builder.ToString();
        }
    }
}
